"""
LangGraph 节点与 START / END 节点详解
=================================

本例说明：
1️⃣ START / END 是什么？
2️⃣ 它们在状态图（StateGraph）中的作用。
3️⃣ 节点之间如何通过边（Edge）连接，形成可执行的数据流。

LangGraph 是一个「状态流驱动」的框架：
- START 表示图的“入口点”，即第一个执行节点的前置节点。
- END   表示图的“出口点”，即最后一个节点的后继节点。
"""

from langchain_core.runnables import RunnableConfig
from langgraph.graph import StateGraph, START, END


# --- Step 1️⃣：定义状态结构 ---
# 我们使用 dict 作为状态（State）类型。
# 每个节点都会接收和返回一个 dict，对应状态的局部更新。
builder = StateGraph(dict)


# --- Step 2️⃣：定义第一个节点 ---
def my_node(state: dict, config: RunnableConfig):
    """
    ✅ 节点1：my_node
    ----------------
    参数：
      - state: 当前图的状态，包含上一个节点的输出。
      - config: 可运行配置（RunnableConfig），包含如 user_id、执行参数等。
    返回：
      - dict，表示局部状态更新（会被 reducer 合并到全局状态中）
    """
    print("🔹 [my_node] 收到 state：", state)
    print("🔹 [my_node] 当前用户ID：", config["configurable"]["user_id"])

    user_input = state.get("input", "Anonymous")
    return {"greet": f"Hello, {user_input}!"}


# --- Step 3️⃣：定义第二个节点 ---
def my_other_node(state: dict):
    """
    ✅ 节点2：my_other_node
    ----------------------
    演示一个不需要 config 参数的节点。
    这个节点读取上一个节点的输出并继续加工。
    """
    print("🔸 [my_other_node] 收到状态：", state)

    # 拼接进一步的输出
    state["greet"] += " Nice to meet you!"
    return state


# --- Step 4️⃣：向状态图添加节点 ---
builder.add_node("my_node", my_node)
builder.add_node("my_other_node", my_other_node)


# --- Step 5️⃣：添加边（Edges）---
# 在 LangGraph 里，边用于指定执行顺序。
# START 和 END 是特殊节点常量：

# ✅ START（入口节点）
# - 表示图的起点。
# - 它本身不会执行逻辑。
# - 它的作用是“告诉图从哪个节点开始执行”。
#   比如这里我们连到 "my_node"，表示流程入口是 my_node。
builder.add_edge(START, "my_node")

# ✅ 普通节点边
# - 表示执行顺序的连接。
builder.add_edge("my_node", "my_other_node")

# ✅ END（结束节点）
# - 表示图的终点。
# - 它本身不执行逻辑，只是告诉 LangGraph
#   当流转到这里时，整个图执行完成。
builder.add_edge("my_other_node", END)


# --- Step 6️⃣：编译状态图 ---
graph = builder.compile()


# --- Step 7️⃣：执行状态图 ---
if __name__ == "__main__":
    # 初始状态（从 START 注入）
    initial_state = {"input": "小易哥"}

    # 配置信息，可被节点访问
    config = RunnableConfig(configurable={"user_id": "user_001"})

    print("\n🚀 开始执行状态图...\n")
    result = graph.invoke(initial_state, config)
    print("\n✅ 最终状态：", result)
